/*
	在面向对象语言中，接口（Interfaces）是一个很重要的概念，它
	是对行为的抽象，而具体如何行动需要由类（classes）去实现（implements）。
*/

interface Person{ // 定义了一个接口 Person, 接口一般首字母大写
	name: string;
	age: number;
}

// 定义了一个变量 tom，它的类型是 Person
// 这样，我们就约束了 tom 的形状必须和接口 Person 一致
let tom: Person = {
	name: 'Tom',
	age: 25
}

// 定义的变量比接口少了一些属性是不允许的
// 多一些属性也是不允许的
// 赋值的时候，变量的形状必须和接口的形状保持一致


/*
	可选属性
	有时希望不要完全匹配一个形状，那么可以用可选属性：
	可选属性的含义是该属性可以不存在
	但是仍然不允许添加未定义的属性：
*/
interface Person{
	name: string;
	age?: number;
}
let tom: Person = {
	name: 'Tom'
}

let tom: Person = {
	name: 'Tom',
	age: 25
}



/*
	任意属性
*/
interface Person{
	name: string;
	age?: number;
	[propName: string]: any;
}
let tom: Person = {
	name: 'Tom',
	gender: 'male'
}

/** 一旦定义了任意属性，那么确定属性和可选属性的类型都必须是它的类型的子集 **/
interface Person {
	name: string;
	age?: number;
	[propName: string]: string;
}
let tom: Person = {
	name: 'Tom',
	age: 25,
	gender: 'male'
};
//上例中，任意属性的值允许是 string，但是可选属性 age 的值却是 number，number 不是 string 的子属性，所以报错了


/**
 * 只读属性
 * 有时候希望对象中的一些字段只能在创建的时候被赋值，那么可以用 readonly 定义只读属性：
**/
interface Person{
	readonly id: number;
	name: string;
	age?: number;
	[propName: string]: any;
}
let tom: Person = {
	id: 8989,
	name: 'Tom',
	gender: 'male'
}
tom.id = 8888
// index.ts(14,5): error TS2540: Cannot assign to 'id' because it is a constant or a read-only property.

//上例中，使用 readonly 定义的属性 id 初始化后，又被赋值了，所以报错了。

//注意，只读的约束存在于第一次给对象赋值的时候，而不是第一次给只读属性赋值的时候：














